package com.maimao.kill.controller;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.common.util.concurrent.RateLimiter;
import com.maimao.core.constant.KillConstant;
import com.maimao.core.model.auth.AuthUser;
import com.maimao.core.model.resp.Result;
import com.maimao.core.utils.DateUtils;
import com.maimao.kill.controller.base.BaseController;
import com.maimao.kill.service.KillGoodsService;
import com.maimao.kill.service.KillService;
import com.maimao.kill.utils.KillUtils;
import com.maimao.model.kill.KillGoods;
import com.maimao.model.kill.KillInterfaceExposer;
import com.maimao.model.kill.dto.KillDto;
import com.maimao.model.kill.input.KillCommonInput;
import io.seata.core.context.RootContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.concurrent.TimeUnit;

/**
 * @author MaoLin Wang
 * @date 2021/4/13 2:09 下午
 */
@Slf4j
@RestController
@RequestMapping("/kill/doKill")
public class KillController extends BaseController {

    @Autowired
    private KillGoodsService killGoodsService;

    @Value("${kill.interface.md5-salt}")
    private String md5Salt;

    @Autowired
    private KillUtils killUtils;

    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private KillService killService;

    /**
     * @deprecated
     */
    @PostMapping("/kill-exposed")
    public Result<?> killExposer(@RequestParam("killId") Long killId) {
        if (killId == null || killId <= 0) {
            return Result.notValid("无效的秒杀信息");
        }
        KillGoods details = killGoodsService.details(killId);
        if (details == null) {
            return Result.notValid("无效的秒杀信息");
        }
        LocalDateTime now = DateUtils.now();
        if (details.getStartTime().compareTo(now) > 0 || details.getEndTime().compareTo(now) < 0) {
            //未开始 或 已结束
            Result result = Result.notValid();
            result.setData(KillInterfaceExposer.builder()
                    .startTime(details.getStartTime().toInstant(ZoneOffset.of("+8")).toEpochMilli())
                    .endTime(details.getEndTime().toInstant(ZoneOffset.of("+8")).toEpochMilli())
                    .now(now.toInstant(ZoneOffset.of("+8")).toEpochMilli())
                    .start(false)
                    .killId(killId)
                    .build());
            return result;
        }
        return Result.okData(KillInterfaceExposer.builder()
                .start(true)
                .killId(killId)
                .start(true)
                .build());

    }

    /**
     * 秒杀接口
     *
     * @param input
     * @return
     */
    @PostMapping("/kill0")
    public Result<?> kill(@RequestBody KillCommonInput input) {
        if (input == null || input.getKillId() == null || input.getKillId() < 1 /*|| StrUtil.isBlank(input.getCode())*/) {
            return Result.notValid("illegal request!");
        }
        AuthUser authUser = checkAndGetAuthUser();
        Long killId = input.getKillId();
        LocalDateTime now = DateUtils.now();

        Object md5 = redisTemplate.opsForValue().get(getKillMd5Key(killId, authUser.getId()));
        if (null == md5 || !md5.toString().equals(input.getCode())) {
            //md5值与生成的不同
            return Result.notValid("illegal request!");
        }
        KillGoods details = killGoodsService.details(killId);
        if (details == null) {
            return Result.notValid("无效的商品");
        }
        if (details.getStartTime().compareTo(now) > 0) {
            return Result.notValid("秒杀尚未开始");
        }
        if (details.getEndTime().compareTo(now) < 0) {
            return Result.notValid("秒杀已结束");
        }
        if (!killService.killByQueue(killId, authUser.getId2Long())) {
            return Result.fail("秒杀失败");
        }
        return Result.ok("秒杀成功，排队中...");
    }

    /**
     * 秒杀失败库存补偿 内部调用
     */
    @PostMapping("/client/$killFailMaiMao$")
    public Result<?> killFail(@RequestBody KillDto dto) {
        if (dto == null || dto.getKillId() == null || dto.getUserId() == null) {
            return Result.notValid();
        }
        killService.killFail(dto.getKillId(), dto.getUserId());
        return Result.ok();
    }

    /**
     * 秒杀下单减少秒杀商品表db库存
     * @return
     */
    @PostMapping("/client/reduceStock")
    public Result<?> reduceStock(@RequestBody KillDto dto){
        if (dto==null||dto.getKillId()==null||dto.getKillId()<=0){
            return Result.notValid();
        }
        HttpServletRequest request = getRequest();
        String xid = request.getHeader(RootContext.KEY_XID);
        RootContext.bind(xid);
        killGoodsService.reduceDbStock(dto.getKillId());
        return Result.ok();
    }
    /*    */

    /**
     * 秒杀生成确认订单 如果是从购物车下单，则可以是多个秒杀商品，需要校验，如果存在非秒杀商品，返回错误
     *
     * @return
     *//*
    @Deprecated
    @PostMapping("/submitOrder")
    public Result<?> submitOrder(@RequestBody KillOrderCheckInput input) {
        if (input == null || ObjectUtil.isEmpty(input.getKillIds())) {
            return Result.notValid();
        }
        List<Long> killIds = input.getKillIds();
        List<KillGoods> killGoodsList = Lists.newArrayListWithCapacity(killIds.size());
        for (Long killId : killIds) {
            KillGoods details = killGoodsService.details(killId);
            if (details == null) {

            }
            killGoodsList.add(details);
        }

        return null;
    }*/
    @GetMapping("/killtest")
    public Result<?> killjemter(@RequestParam("killId") Long killId, @RequestParam("userId") Long userId) {
//        AuthUser authUser = checkAndGetAuthUser();
        if (!rateLimiter.tryAcquire(100,TimeUnit.MILLISECONDS)){
            log.error("人太多了");
            return Result.fail("人太多了！");
        }
        KillGoods details = killGoodsService.details(killId);
        if (details == null) {
            return Result.notValid("无效的商品");
        }
        if (!killService.killByRedisson(killId, userId)) {
            return Result.fail("秒杀失败");
        }
        return Result.ok("秒杀成功");


    }

    private RateLimiter rateLimiter=RateLimiter.create(400);
    @GetMapping("/killtest2")
    public Result<?> killjemter2(@RequestParam("killId") Long killId) {
        if (!rateLimiter.tryAcquire(100,TimeUnit.MILLISECONDS)){
            log.error("人太多了");
            return Result.fail("人太多了！");
        }
        AuthUser authUser = checkAndGetAuthUser();
        KillGoods details = killGoodsService.details(killId);
        if (details == null) {
            return Result.notValid("无效的商品");
        }
        if (!killService.killByQueue(killId, authUser.getId2Long())) {
            return Result.fail("秒杀失败");
        }
        return Result.ok("秒杀成功");


    }

    /**
     * 校验图形验证码 校验通过生成秒杀接口md5值
     */
    @PostMapping("/verifyCode")
    public Result<?> verifyCode(@RequestBody KillCommonInput input) {
        if (input == null || input.getKillId() == null || input.getCode() == null || input.getKillId() < 1) {
            return Result.notValid("验证码错误");
        }
        AuthUser authUser = checkAndGetAuthUser();
        String codeKey = getCodeKey(input.getKillId(), authUser.getId());
        Object o = redisTemplate.opsForValue().get(codeKey);
        if (null != o) {
            if (o.toString().equals(input.getCode())) {
                //校验成功
                //生成接口md5值
                String md5 = killUtils.md5(input.getKillId(), authUser.getId2Long(), md5Salt);
                redisTemplate.opsForValue().set(
                        getKillMd5Key(input.getKillId(), authUser.getId()),
                        md5,
                        KillConstant.DEFAULT_KILL_MD5, TimeUnit.SECONDS);
                return Result.okData(md5);
            }
            return Result.notValid("验证码错误");
        }
        return Result.notValid("验证码已过期，请刷新验证码");
    }


    private String getKillMd5Key(Long killId, String userId) {
        return KillConstant.KILL_MD5_INTERFACE_KEY + killId + userId;
    }

    /**
     * 生成秒杀图形验证码
     */
    @GetMapping("/kill-code")
    public void imageCode(@RequestParam("killId") Long killId) throws IOException {
        if (killId == null) {
            return;
        }
        // 获取验证码字符串
        String code = defaultKaptcha.createText();
        log.info("生成图形验证码: {}" + code);
        AuthUser authUser = checkAndGetAuthUser();
        String key = getCodeKey(killId, authUser.getId());
        redisTemplate.opsForValue().set(key, code, 1, TimeUnit.MINUTES);
        // 获取验证码图片
        BufferedImage image = defaultKaptcha.createImage(code);
        // 将验证码图片写出去
        ServletOutputStream out = getResponse().getOutputStream();
        ImageIO.write(image, "jpg", out);
    }

    private String getCodeKey(Long killId, String userId) {
        return KillConstant.KILL_CODE_KEY + killId + userId;
    }

}
